#pragma once
#include "HttpResponse.h"
#include <map>
#include <sstream>

template<typename T>
class RequestParamHelper
{
public:
	static std::wstring ToString(const T& value)
	{
		std::wstringstream ss;
		ss << value;
		return ss.str();
	}
};

template<>
class RequestParamHelper<bool>
{
public:
	static std::wstring ToString(const bool& value)
	{
		return value ? L"true" : L"false";
	}
};

//
// HttpRequest
//
class HttpRequest
{
public:
	typedef std::map<std::wstring, std::wstring> ParamMap;
	class ParamBase
	{
	public:
		ParamBase(HttpRequest* req, const wchar_t* name, const wchar_t* defaultValue) 
			: Name(name), DefaultValue(defaultValue), Next(NULL)
		{
			req->AddParam(this);
		}
		virtual ~ParamBase() {}

		virtual std::wstring ValueStr() const = 0;

		const wchar_t* Name;
		const wchar_t* DefaultValue;
		ParamBase* Next;
	};

	template<typename T>
	class Param : public ParamBase
	{
	public:
		Param(HttpRequest* req, const wchar_t* name, const wchar_t* defaultValue, const T& initValue)
			: ParamBase(req, name, defaultValue), Value(initValue)
		{}

		std::wstring ValueStr() const
		{
			return RequestParamHelper<T>::ToString(Value);
		}

		T& operator*() { return Value; }
		const T& operator*() const { return Value; }
		void operator=(const T& v) { Value = v; }

		T Value;
	};

public:
	HttpRequest() : mParams(NULL) {}
	virtual ~HttpRequest() {}

	virtual HttpResponse* getResponse() = 0;
	virtual const wchar_t* GetApiName() = 0;

	void DefineParams(ParamMap& params) const
	{
		const ParamBase* param = mParams;
		while (param != NULL)
		{
			std::wstring valueStr = param->ValueStr();
			if (valueStr != param->DefaultValue)
				params[param->Name] = valueStr;
			param = param->Next;
		}
	}

	virtual bool Validate() { return true; }

	// hack the compiler.
	HttpRequest* Ptr() { return this; }

	void AddParam(ParamBase* param)
	{
		param->Next = mParams;
		mParams = param;
	}

private:
	ParamBase* mParams;
};
